using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Xml;
using System.Xml.Linq;

namespace GuavaData
{
    public class Project : Operator
    {
        // Relational algebra project operator, list of column aliases to project
        // Columns (and domains) will be in the order of the columns to project in the output

        #region Fields
        Operator child;
        public Operator Child
        {
            get { return child; }
            set { child = value; }
        }
        #endregion Fields

        public List<string> toProject;
        public Project(Operator child, IEnumerable<string> columnsToProject)
        {
            this.child = child;
            child.parent = this;
            toProject = new List<string>(columnsToProject);

            // Assemble the columns for output, and perform basic query checking
            this.exposedColumns = new List<string>();
            this.exposedDomains = new List<GuavaData.Domain.Domain>();
            for (int i = 0; i < child.exposedColumns.Count; i++)
            {
                foreach (String s in toProject)
                {
                    if (s.EndsWith(child.exposedColumns[i]) || s.StartsWith(child.exposedColumns[i]))
                    {
                        this.exposedColumns.Add(child.exposedColumns[i]);
                        this.exposedDomains.Add(child.exposedDomains[i]);
                        break;
                    }
                }
            }

            // Dummy check - same number of columns as expected
            if (this.exposedColumns.Count != toProject.Count)
            {
                throw new Exception("Not all columns in the project list appear in the base query.");
            }
        }

        public override SqlText Visit(Provider qv)
        {
            return qv.Transform(this);
        }
        public override void Visit(Transform t, Command c)
        {
            t.Expand(this, c);
        }

        public override Operator Clone()
        {
            return new Project(this.child.Clone(), this.exposedColumns);
        }

        public override void NotifyChange(Operator old, Operator newOp)
        {
            if (this.child == old)
            {
                this.child = newOp;
                newOp.parent = this;
            }
        }

        public override void Visit(Channel c, string table)
        {
            c.MapAliases(this, table);
        }

        new public static Project FromXElement(XElement x)
        {
        
            Operator child = null;
            List<string> columns = new List<string>();

            foreach (XElement att in x.Elements())
            {
                if (att.Name.LocalName.Equals("operator")) child = Operator.FromXElement(att);
                else if (att.Name.LocalName.Equals("projectList"))
                {
                    foreach (XElement column in att.Elements())
                    {
                        columns.Add(column.Value);
                    }
                }
            }

            if (!(child == null))
                return new Project(child, columns);
            else
                throw new Exception("While loading Project from XML: child was null");
        }

    }
}
